﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System.Collections.Generic;
using System.Linq;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using ScrumTable.Common;
using ScrumTable.Common.Collections;
using ScrumTable.DL.Data.TFS.Properties;

#endregion


namespace ScrumTable.DL.Data.TFS.Services.TeamFoundation
{
    /// <summary>
    /// This class provides additiona functionalities for work item link
    /// management.
    /// </summary>
    public class TfsLinkHandler
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private const string LinkType = "System.LinkTypes.Hierarchy";

        private readonly WorkItem _workItem;
        private readonly WorkItemLinkTypeEnd _parentTypeEnd;
        private readonly WorkItemLinkTypeEnd _childTypeEnd;

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        /// <summary>
        /// Gets a set of child links.
        /// </summary>
        public IEnumerable<WorkItemLink> ChildLinks
        {
            get
            {
                return from link in _workItem.WorkItemLinks.ToEnumerable<WorkItemLink>()
                       where link.LinkTypeEnd.Id == _childTypeEnd.Id
                       select link;
            }
        }

        /// <summary>
        /// Gets the parent work item link instance, if it is available.
        /// </summary>
        public WorkItemLink ParentLink
        {
            get
            {
                return (from link in _workItem.WorkItemLinks.ToEnumerable<WorkItemLink>()
                       where link.LinkTypeEnd.Id == _parentTypeEnd.Id
                       select link).FirstOrDefault();
            }
        }

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates a new TfsLinkHandler instance.
        /// </summary>
        public TfsLinkHandler(WorkItem workItem)
        {
            PreCondition.AssertNotNull(workItem, "workItem");
            PreCondition.AssertTrue(LinksAvaiable(workItem.Store), Resources.ExcPreConMissingWiLinks);
            _workItem = workItem;

            _parentTypeEnd = _workItem.Store.WorkItemLinkTypes[LinkType].ReverseEnd;
            _childTypeEnd = _workItem.Store.WorkItemLinkTypes[LinkType].ForwardEnd;
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Returns true if the required workitem links are available on server side.
        /// </summary>
        /// <param name="store">Specifies the workitem store to check.</param>
        public static bool LinksAvaiable(WorkItemStore store)
        {
            return (store != null
                    && store.WorkItemLinkTypes.Contains(LinkType)
                    && store.WorkItemLinkTypes[LinkType].ForwardEnd != null
                    && store.WorkItemLinkTypes[LinkType].ReverseEnd != null);
        }

        /// <summary>
        /// Sets the parent link of the underlying work item.
        /// </summary>
        /// <param name="linkId">Specifies the id of the parent element.</param>
        public void AddParentLink(int linkId)
        {
            int existingLink = SearchLink(_parentTypeEnd);

            if (existingLink != -1)
                _workItem.WorkItemLinks.RemoveAt(existingLink);

            _workItem.WorkItemLinks.Add(new WorkItemLink(_parentTypeEnd, linkId));
        }

        /// <summary>
        /// Removes a parent link from the underlying work item.
        /// </summary>
        /// <param name="linkId">Specifies the id of the parent element.</param>
        public void RemoveParentLink(int linkId)
        {
            int existingLink = SearchLink(_parentTypeEnd, linkId);

            if (existingLink != -1)
                _workItem.WorkItemLinks.RemoveAt(existingLink);
        }

        /// <summary>
        /// Adds a child link to the underlying work item.
        /// </summary>
        /// <param name="linkId">Specifies the id of the child element.</param>
        public void AddChildLink(int linkId)
        {
            int existingLink = SearchLink(_childTypeEnd, linkId);

            if (existingLink == -1)
                _workItem.WorkItemLinks.Add(new WorkItemLink(_childTypeEnd, linkId));
        }

        /// <summary>
        /// Adds a child link to the underlying work item.
        /// </summary>
        /// <param name="linkId">Specifies the id of the child element.</param>
        public void RemoveChildLink(int linkId)
        {
            int existingLink = SearchLink(_childTypeEnd, linkId);

            if (existingLink != -1)
                _workItem.WorkItemLinks.RemoveAt(existingLink);
        }

        private int SearchLink(WorkItemLinkTypeEnd linkTypeEnd, int targetId)
        {
            for (int i = 0; i < _workItem.WorkItemLinks.Count; ++i)
            {
                if (_workItem.WorkItemLinks[i].TargetId == targetId && _workItem.WorkItemLinks[i].LinkTypeEnd.Id == linkTypeEnd.Id)
                    return i;
            }
            return -1;
        }

        private int SearchLink(WorkItemLinkTypeEnd linkTypeEnd)
        {
            for (int i = 0; i < _workItem.WorkItemLinks.Count; ++i)
            {
                if (_workItem.WorkItemLinks[i].LinkTypeEnd.Id == linkTypeEnd.Id)
                    return i;
            }
            return -1;
        }

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion
    }
}